package org.feuyeux.opentracing.hello;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.web.servlet.context.ServletWebServerInitializedEvent;
import org.springframework.cloud.sleuth.Span;
import org.springframework.cloud.sleuth.Tracer;
import org.springframework.context.ApplicationListener;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

import java.util.Random;
import java.util.concurrent.TimeUnit;

@RestController
public class HelloController implements ApplicationListener<ServletWebServerInitializedEvent> {
    private static final Logger log = LoggerFactory.getLogger(HelloController.class);
    private final Random random = new Random();
    private int port;
    @Autowired
    private RestTemplate restTemplate;
    @Autowired
    private Tracer tracer;

    @RequestMapping("/")
    public String home() {
        log.info("Handling home");
        Span span = this.tracer.currentSpan();
        if (span != null) {
            span.tag("port", String.valueOf(this.port));
            span.event("RESTful Access");
        }
        String s = this.restTemplate.getForObject("http://localhost:" + this.port + "/hi", String.class);
        return "hi " + s;
    }

    @RequestMapping("/hi")
    public String hi() throws InterruptedException {
        log.info("say hi");
        int millis = sleep();
        Span span = this.tracer.currentSpan();
        if (span != null) {
            span.tag("hi-sleep", String.valueOf(millis));
        }
        return who();
    }

    private String who() throws InterruptedException {
        log.info("find who");
        Span newSpan = this.tracer.nextSpan().name("hi2who");
        try (Tracer.SpanInScope ws = this.tracer.withSpan(newSpan.start())) {
            int millis = sleep();
            newSpan.tag("who-sleep", String.valueOf(millis));
            newSpan.tag("inner.invoker", this.getClass().getName());
            newSpan.event("Call Me");
        } finally {
            newSpan.end();
        }
        return System.getenv("USER");
    }

    private int sleep() throws InterruptedException {
        int millis = this.random.nextInt(1000);
        TimeUnit.MILLISECONDS.sleep(millis);
        return millis;
    }

    @Override
    public void onApplicationEvent(ServletWebServerInitializedEvent event) {
        this.port = event.getSource().getPort();
    }
}
